extends Node
#牌型验证规则
class_name MahjongVerificationRules

#出牌验证---start
func verifySelectedTile(selectedTileIdArr):
	# 1.统计对子详情
	var pairDetailObj = pairDetail(selectedTileIdArr)
	var pongDetailObj = pongDetail(selectedTileIdArr)
	var kanDetailObj = kanDetail(selectedTileIdArr)
	var smallShunDetailObj = smallShunDetail(selectedTileIdArr)
	var bigShunDetailObj = bigShunDetail(selectedTileIdArr)
	var zfbDetailObj = zfbDetail(selectedTileIdArr)
	var fengDetailObj = fengDetail(selectedTileIdArr)
	#返回结果
	var verifyObj = {
		"pairDetailObj":pairDetailObj,
		"pongDetailObj":pongDetailObj,
		"kanDetailObj":kanDetailObj,
		"smallShunDetailObj":smallShunDetailObj,
		"bigShunDetailObj":bigShunDetailObj,
		"zfbDetailObj":zfbDetailObj,
		"fengDetailObj":fengDetailObj
	}
	return verifyObj

# 1.统计对子详情
func pairDetail(selectedTileIdArr):
	var counts = {}  # 用于存储每种牌的出现次数
	var usedPairs = {}  # 用于记录已经计算过的对子，避免重复
	var pairDetail = []  # 用于存储对子类型
	var pairCount = 0  # 记录对子数量
	var tileGroups = {}  # 用于存储每种牌的所有 mahjong_id（为了更高效地匹配）
	# 统计每种牌的数量，并将牌的 ID 存储到 tileGroups 中
	for tileId in selectedTileIdArr:
		var mahjongType = "_".join(tileId.split("_").slice(0, 2))  # 提取 'wan_1'
		counts[mahjongType] = counts.get(mahjongType, 0) + 1
		# 将同类牌的 ID 存储在 tileGroups 中
		if not tileGroups.has(mahjongType):
			tileGroups[mahjongType] = []
		tileGroups[mahjongType].append(tileId)
	# 遍历每种牌类型，计算对子
	for card_type in counts.keys():
		if counts[card_type] >= 2 and not usedPairs.has(card_type):
			pairCount += 1
			usedPairs[card_type] = true  # 标记已计算该对子
			pairDetail.append(card_type)
	var pairDetailObj = {
		"pairCount": pairCount,
		"pairDetail": pairDetail
	}
	# 通过对子类型和 tileGroups 生成具体的对子详情
	var pairDetailArr = []
	if pairDetailObj.pairCount > 0:
		for currentPair in pairDetailObj.pairDetail:
			var currentPairArr = []
			var loopTimes = 0
			# 从 tileGroups 中获取当前对子类型的所有牌
			for tileId in tileGroups[currentPair]:
				if loopTimes == 2: break
				currentPairArr.append(tileId)
				loopTimes += 1
			pairDetailArr.append(currentPairArr)

	return {
		"pairCount":pairCount,
		"pairDetailArr":pairDetailArr
	}
# 2.统计碰子详情
func pongDetail(selectedTileIdArr):
	var counts = {}  # 用于存储每种牌的出现次数
	var usedPongs = {}  # 用于记录已经计算过的对子，避免重复
	var pongDetail = []  # 用于存储对子类型
	var pongCount = 0  # 记录对子数量
	var tileGroups = {}  # 用于存储每种牌的所有 mahjong_id（为了更高效地匹配）
	# 统计每种牌的数量，并将牌的 ID 存储到 tileGroups 中
	for tileId in selectedTileIdArr:
		var mahjongType = "_".join(tileId.split("_").slice(0, 2))  # 提取 'wan_1'
		counts[mahjongType] = counts.get(mahjongType, 0) + 1
		# 将同类牌的 ID 存储在 tileGroups 中
		if not tileGroups.has(mahjongType):
			tileGroups[mahjongType] = []
		tileGroups[mahjongType].append(tileId)
	# 遍历每种牌类型，计算对子
	for card_type in counts.keys():
		if counts[card_type] >= 3 and not usedPongs.has(card_type):
			pongCount += 1
			usedPongs[card_type] = true  # 标记已计算该对子
			pongDetail.append(card_type)
	var pongDetailObj = {
		"pongCount": pongCount,
		"pongDetail": pongDetail
	}
	# 通过对子类型和 tileGroups 生成具体的对子详情
	var pongDetailArr = []
	if pongDetailObj.pongCount > 0:
		for currentPong in pongDetailObj.pongDetail:
			var currentPongArr = []
			var loopTimes = 0
			# 从 tileGroups 中获取当前对子类型的所有牌
			for tileId in tileGroups[currentPong]:
				if loopTimes == 3: break
				currentPongArr.append(tileId)
				loopTimes += 1
			pongDetailArr.append(currentPongArr)

	return {
		"pongCount":pongCount,
		"pongDetailArr":pongDetailArr
	}
# 3.统计杠子详情
func kanDetail(selectedTileIdArr):
	var counts = {}  # 用于存储每种牌的出现次数
	var usedKans = {}  # 用于记录已经计算过的对子，避免重复
	var kanDetail = []  # 用于存储对子类型
	var kanCount = 0  # 记录对子数量
	var tileGroups = {}  # 用于存储每种牌的所有 mahjong_id（为了更高效地匹配）
	# 统计每种牌的数量，并将牌的 ID 存储到 tileGroups 中
	for tileId in selectedTileIdArr:
		var mahjongType = "_".join(tileId.split("_").slice(0, 2))  # 提取 'wan_1'
		counts[mahjongType] = counts.get(mahjongType, 0) + 1
		# 将同类牌的 ID 存储在 tileGroups 中
		if not tileGroups.has(mahjongType):
			tileGroups[mahjongType] = []
		tileGroups[mahjongType].append(tileId)
	# 遍历每种牌类型，计算对子
	for card_type in counts.keys():
		if counts[card_type] >= 4 and not usedKans.has(card_type):
			kanCount += 1
			usedKans[card_type] = true  # 标记已计算该对子
			kanDetail.append(card_type)
	var kanDetailObj = {
		"kanCount": kanCount,
		"kanDetail": kanDetail
	}
	# 通过对子类型和 tileGroups 生成具体的对子详情
	var kanDetailArr = []
	if kanDetailObj.kanCount > 0:
		for currentKan in kanDetailObj.kanDetail:
			var currentKanArr = []
			var loopTimes = 0
			# 从 tileGroups 中获取当前对子类型的所有牌
			for tileId in tileGroups[currentKan]:
				if loopTimes == 4: break
				currentKanArr.append(tileId)
				loopTimes += 1
			kanDetailArr.append(currentKanArr)

	return {
		"kanCount":kanCount,
		"kanDetailArr":kanDetailArr
	}
# 4.统计小顺详情
func smallShunDetail(selectedTileIdArr):
	var suitNumbers = {}  # 用于按花色存储数字，键为花色（例如 "tiao"），值为该花色中出现的牌号数组
	var suitMahjongIds = {}  # 用于存储每种牌对应的 `mahjong_id`
	# 遍历所有选中的牌，分解牌的ID，并存入对应花色的数组（避免重复）
	for tileId in selectedTileIdArr:
		var parts = tileId.split("_")
		var suit = parts[0]         # 花色，如 "tiao"
		var number = int(parts[1])  # 牌号，如 4
		if suitNumbers.has(suit):
			if not suitNumbers[suit].has(number):
				suitNumbers[suit].append(number)
				suitMahjongIds[suit].append(tileId)  # 存储 mahjong_id
		else:
			suitNumbers[suit] = [number]
			suitMahjongIds[suit] = [tileId]  # 存储第一个牌的 mahjong_id
	# 对每个花色的牌号进行排序，便于查找连续数字
	for suit in suitNumbers.keys():
		suitNumbers[suit].sort()
	var smallShunCount = 0  # 用于记录小顺的数量
	var smallShunDetails = []  # 用于记录小顺组成的 mahjong_id
	# 遍历每个花色，查找是否存在连续的3张牌（小顺）
	for suit in suitNumbers.keys():
		var numbers = suitNumbers[suit]
		# 依次遍历排序后的牌号，检查是否有 num, num+1, num+2 连续的牌
		for i in range(0, numbers.size() - 2):  # -2 确保能够有 3 张牌
			if numbers[i+1] == numbers[i] + 1 and numbers[i+2] == numbers[i] + 2:
				smallShunCount += 1
				# 找到的小顺的 mahjong_id
				smallShunDetails.append([
					suit + "_" + str(numbers[i]),
					suit + "_" + str(numbers[i+1]),
					suit + "_" + str(numbers[i+2])
				])
	var smallShunDetailArr = []
	if smallShunCount > 0:
		for currentSmallShun in smallShunDetails:
			var currentSmallShunArr = []
			for i in currentSmallShun:
				var loopTimes = 0
				for j in selectedTileIdArr:
					if loopTimes == 1: continue
					if i == "_".join(j.split("_").slice(0, 2)):
						currentSmallShunArr.append(j)
						loopTimes += 1
			smallShunDetailArr.append(currentSmallShunArr)
	return {"smallShunCount": smallShunCount, "smallShunDetailArr": smallShunDetailArr}
# 5.统计大顺详情
func bigShunDetail(selectedTileIdArr):
	var suitNumbers = {}  # 用于按花色存储数字，键为花色（例如 "tiao"），值为该花色中出现的牌号数组
	var suitMahjongIds = {}  # 用于存储每种牌对应的 `mahjong_id`
	# 遍历所有选中的牌，分解牌的ID，并存入对应花色的数组（避免重复）
	for tileId in selectedTileIdArr:
		var parts = tileId.split("_")
		var suit = parts[0]         # 花色，如 "tiao"
		var number = int(parts[1])  # 牌号，如 4
		if suitNumbers.has(suit):
			if not suitNumbers[suit].has(number):
				suitNumbers[suit].append(number)
				suitMahjongIds[suit].append(tileId)  # 存储 mahjong_id
		else:
			suitNumbers[suit] = [number]
			suitMahjongIds[suit] = [tileId]  # 存储第一个牌的 mahjong_id
	# 对每个花色的牌号进行排序，便于查找连续数字
	for suit in suitNumbers.keys():
		suitNumbers[suit].sort()
	var bigShunCount = 0  # 用于记录小顺的数量
	var bigShunDetails = []  # 用于记录小顺组成的 mahjong_id
	# 遍历每个花色，查找是否存在连续的3张牌（小顺）
	for suit in suitNumbers.keys():
		var numbers = suitNumbers[suit]
		# 依次遍历排序后的牌号，检查是否有 num, num+1, num+2 连续的牌
		for i in range(0, numbers.size() - 5):  # -2 确保能够有 3 张牌
			if numbers[i+1] == numbers[i] + 1 and numbers[i+2] == numbers[i] + 2 and numbers[i+3] == numbers[i] + 3 and numbers[i+4] == numbers[i] + 4 and numbers[i+5] == numbers[i] + 5:
				bigShunCount += 1
				# 找到的小顺的 mahjong_id
				bigShunDetails.append([
					suit + "_" + str(numbers[i]),
					suit + "_" + str(numbers[i+1]),
					suit + "_" + str(numbers[i+2]),
					suit + "_" + str(numbers[i+3]),
					suit + "_" + str(numbers[i+4]),
					suit + "_" + str(numbers[i+5])
				])
	var bigShunDetailArr = []
	if bigShunCount > 0:
		for currentBigShun in bigShunDetails:
			var currentBigShunArr = []
			for i in currentBigShun:
				var loopTimes = 0
				for j in selectedTileIdArr:
					if loopTimes == 1: continue
					if i == "_".join(j.split("_").slice(0, 2)):
						currentBigShunArr.append(j)
						loopTimes += 1
			bigShunDetailArr.append(currentBigShunArr)
	return {"bigShunCount": bigShunCount, "bigShunDetailArr": bigShunDetailArr}
# 6.统计中发白详情
func zfbDetail(selectedTileIdArr):
	var normalizedSet = {}
	# 遍历所有选中的牌，标准化并存入字典
	for tileId in selectedTileIdArr:
		var parts = tileId.split("_")
		var cardType = parts[0] + "_" + parts[1]  # 如 "hongzhong_1"
		normalizedSet[cardType] = true
	# 检查是否有中发白组合
	var zfbCount
	if normalizedSet.has("hongzhong_1") and normalizedSet.has("facai_1") and normalizedSet.has("baiban_1"):
		zfbCount = 1  # 如果有中发白的三张组合，返回1
	else:
		zfbCount = 0
	var zfbDetailArr = []
	if zfbCount > 0:
		var currentZfbDetailArr = []
		var target_ids = ["hongzhong_1", "facai_1", "baiban_1"]
		for tileId in selectedTileIdArr:
			var suit = "_".join(tileId.split("_").slice(0, 2))  # 获取花色和牌号
			if suit in target_ids:
				currentZfbDetailArr.append(tileId)
				target_ids.erase(suit)  # 一旦找到目标牌，移除它，避免重复添加
			if target_ids.size() == 0:  # 如果所有目标都已经找到，提前退出循环
				break
		zfbDetailArr.append(currentZfbDetailArr)
	return {
		"zfbCount":zfbCount,
		"zfbDetailArr":zfbDetailArr
	}
# 7.统计东南西北详情
func fengDetail(selectedTileIdArr):
	var normalizedSet = {}
	# 遍历所有选中的牌，标准化并存入字典
	for tileId in selectedTileIdArr:
		var parts = tileId.split("_")
		var cardType = parts[0] + "_" + parts[1]  # 如 "dong_1"
		normalizedSet[cardType] = true
	
	var fengCount
	# 检查是否有东南西北风组合
	if normalizedSet.has("dong_1") and normalizedSet.has("nan_1") and normalizedSet.has("xi_1") and normalizedSet.has("bei_1"):
		fengCount = 1  # 如果有东南西北风的四张组合，返回1
	else:
		fengCount = 0
	var fengDetailArr = []
	if fengCount > 0:
		var currentFengDetailArr = []
		var target_ids = ["dong_1", "nan_1", "xi_1","bei_1"]
		for tileId in selectedTileIdArr:
			var suit = "_".join(tileId.split("_").slice(0, 2))  # 获取花色和牌号
			if suit in target_ids:
				currentFengDetailArr.append(tileId)
				target_ids.erase(suit)  # 一旦找到目标牌，移除它，避免重复添加
			if target_ids.size() == 0:  # 如果所有目标都已经找到，提前退出循环
				break
		fengDetailArr.append(currentFengDetailArr)
	return {
		"fengCount":fengCount,
		"fengDetailArr":fengDetailArr
	}
#出牌验证---end




#胡牌验证---start
#1.牌id转换
func convert_card_id(cards: Array) -> Array:
	var handConstId = []
	for item in cards:
		var id = item.split("_")[0] + "_" + item.split("_")[1]
		handConstId.append(id)
	
	var card_map = {
	"wan_1": 01, "wan_2": 02, "wan_3": 03, "wan_4": 04, "wan_5": 05, "wan_6": 06, "wan_7": 07, "wan_8": 08, "wan_9": 09,
	"tong_1": 11, "tong_2": 12, "tong_3": 13, "tong_4": 14, "tong_5": 15, "tong_6": 16, "tong_7": 17, "tong_8": 18, "tong_9": 19,
	"tiao_1": 21, "tiao_2": 22, "tiao_3": 23, "tiao_4": 24, "tiao_5": 25, "tiao_6": 26, "tiao_7": 27, "tiao_8": 28, "tiao_9": 29,
	"dong_1": 31, "nan_1": 33, "xi_1": 35, "bei_1": 37,
	"hongzhong_1": 41, "facai_1": 43, "baiban_1": 45
	}
	var converted_cards = []
	# 遍历每张牌，将牌转换为对应的数字
	for card in handConstId:
		if card_map.has(card):  # 如果该牌存在于映射中
			converted_cards.append(card_map[card])
	return converted_cards

#2.验证胡牌主逻辑----start
func can_hu(cards: Array, laizi_count: int):
	# 如果牌张数不是2、5、8、11、14，则不能胡
	if (cards.size() + laizi_count + 1) % 3 != 0:
		return false
	
	# 排序方便胡牌判断
	cards.sort()

	# 依次删除一对牌做将，其余牌全部成扑则可胡
	for i in range(cards.size()):
		if i > 0 and cards[i] == cards[i - 1]:
			# 和上一次是同样的牌，避免重复计算
			continue
		if i + 1 < cards.size() and cards[i] == cards[i + 1] or laizi_count > 0:
			# 找到对子，或是用一张癞子拼出的对子
			var pu_cards = cards.duplicate()  # 复制牌堆
			var pu_laizi = laizi_count
			pu_cards.remove_at(i)
			
			if pu_cards[i] == cards[i]:
				pu_cards.remove_at(i)
			else:
				pu_laizi -= 1
			
			# 删除对子后，检查剩下的牌是否成扑
			if is_shun_ke(pu_cards, pu_laizi):
				return true
	
	if laizi_count >= 2 and is_shun_ke(cards, laizi_count - 2):
		# 两个癞子做将牌特殊判定处理
		return true
	
	return false

func is_shun_ke(cards: Array, laizi_count: int) -> bool:
	if cards.size() == 0:
		return true
	# 若第一张是顺子中的一张
	for first in range(cards[0] - 2, cards[0] + 1):
		if first % 10 > 7 or (laizi_count == 0 and first < cards[0]):
			continue

		var shun_count = 0
		for i in range(3):
			if cards.find(first + i) >= 0:
				shun_count += 1

		if shun_count == 3 or shun_count + laizi_count >= 3:
			var pu_cards = cards.duplicate()
			var pu_laizi = laizi_count
			for i in range(3):
				var delete_pos = pu_cards.find(first + i)
				if delete_pos >= 0:
					pu_cards.remove_at(delete_pos)
				else:
					pu_laizi -= 1

			if is_shun_ke(pu_cards, pu_laizi):
				return true

	# 若第一张是刻子中的一张
	var kezi_count = 1
	var kezi_card = cards[0]

	if cards[1] == kezi_card:
		kezi_count += 1
	if cards[2] == kezi_card:
		kezi_count += 1

	if kezi_count == 3 or kezi_count + laizi_count >= 3:
		var pu_cards = cards.duplicate()
		var pu_laizi = laizi_count
		for i in range(3):
			var delete_pos = pu_cards.find(kezi_card)
			if delete_pos >= 0:
				pu_cards.remove_at(delete_pos)
			else:
				pu_laizi -= 1

		if is_shun_ke(pu_cards, pu_laizi):
			return true

	return false
#验证胡牌主逻辑----end
#出牌验证---end
